;; ==========================================================
;; datasim.lsp This file contains methods for simulating data
;; Original version written by David Flora
;; Copyright (c) 1995-99 by Forrest W. Young
;; ==========================================================

     
(defun simulate-data ()
"Function Args: none
Function to construct simulated multivariate data and to display visualization of the central limit theorem. Show datasheet if no visualization. Returns list of data object and plot-object (nil if no visualization)"
  (let ((result (do-the-simulation)))
    result))


(defun do-the-simulation ()
"Function Args: none
Function to construct simulated multivariate data and to display visualization of the central limit theorem. Returns list of data object and plot-object (nil if no visualization)"
  (let* ((dialog-results (sd-dialog)) 
         (data nil)
         (nobs  nil)
         (nvars nil)
         (nvars-initial nil)
         (visual? nil)
         (dob nil)
         (dob-means nil)
         (dob-stdvs nil)
         (xy nil)
         (h nil)
         (splot nil)
         (plot00 nil)
         (plot01 nil))
    (when 
     dialog-results
     (setf nobs  (select dialog-results 1))
     (setf nvars (select dialog-results 2))
     (setf visual? (select dialog-results 3))
     (setf nvars-initial nvars)
     (when visual? (setf nvars-initial (max nvars 3)))
     (setf data (combine (transpose 
          (matrix (list nvars-initial nobs) 
                  (sample-data nvars-initial dialog-results)))))
     (setf dob 
           (data (strcat (select 
                          (list "Normal" "T" "F" "Uniform" "Binomial"
                                "Chi-Sq" "Cauchy" "Poisson" "Beta Data" "Gamma")
                          (select dialog-results 0)) " Random Data")
                 :title "Simulated Data" 
              ;   :new-data t
                 :variables (mapcar 
                             #'(lambda (x) 
                                 (format nil "Sample~a" x)) (1+ (iseq nvars-initial)))
                 :datatype "multivariate"
                 :data data))
     (send dob :simulate-parameters dialog-results)
     (send dob :about (strcat (send dob :title) " created by ViSta"))
     (setf dob-means (send dob :means))
     (setf dob-stdvs (send dob :standard-deviations))
     (setf xy (send dob :pop-distribution dialog-results))

     (when 
      visual?
      ;#+containers
      ;(progn
      ; (send *watcher* :write-text "Constructing Container")
      ; (setf *spreadplot-container* 
      ;       (make-container :size (send *vista* :spreadplot-sizes) 
      ;                       :free *free-spreadplots*
      ;                       :local-menus *free-spreadplots*
      ;                       :type 1;7 3
      ;                       :show nil)))
      (send dob :create-spreadplot-container)
      (setf splot (spread-plot (matrix '(2 2) 
         (list (plot-lines (first xy) (second xy)
                           :title "Population Distribution" :show nil 
                           :variable-labels '("Population-Scores" "Density"))
               (histogram dob-means 
                          :title "Sample Means" :show nil 
                          :variable-labels '("Sample Means"))
               (histogram (last (column-list (send dob :data-matrix)))
                          :title "Sample Distribution" :show nil
                          :variable-labels '("Sample Values"))
               (histogram dob-stdvs 
                          :title "Sample Standard Deviations" :show nil
                          :variable-labels '("Sample StDevs"))
               ))
             :statistical-object dob :show nil))
      (setf plot00 (select (send splot :plot-matrix) 0 0))
      (setf plot01 (select (send splot :plot-matrix) 0 1))
      (setf plot10 (select (send splot :plot-matrix) 1 0))
      (setf plot11 (select (send splot :plot-matrix) 1 1))
      #+containers
      (progn
       (send *watcher* :write-text "Making Messaging System")
       (apply #'send *spreadplot-container* :location 
              (send *vista* :workmap-location))
       (apply #'send *spreadplot-container* :size 
              (send *vista* :spreadplot-sizes))
      ; (send *spreadplot-container* :show-window) 
      ; (refresh-spreadplot)
       (disable-container)
       )
      
      (send plot00 :menu nil)
      (send plot01 :menu nil)
      (send plot10 :menu nil)
      (send plot11 :menu nil)
      (send plot01 :add-mouse-mode 'nothing)
      (send plot01 :mouse-mode 'nothing)
      (send plot10 :add-mouse-mode 'nothing)
      (send plot10 :mouse-mode 'nothing)
      (send plot11 :add-mouse-mode 'nothing)
      (send plot11 :mouse-mode 'nothing)
      (setf h (+ 1 (round (* 1.5 (+ (send plot00 :text-ascent) 
                                    (send plot00 :text-descent))))))
      (send plot00 :margin 0 h 0 h)
      (send plot01 :margin 0 h 0 0)
      (send plot10 :margin 0 h 0 0)
      (send plot11 :margin 0 h 0 0)
      (send plot00 :add-overlay (send newsamp-overlay-proto :new))
      (send plot00 :plot-buttons :new-x nil :new-y nil :mouse-mode nil
                   :hot-spot nil)
      (send plot00 :margin 0 (second (send plot00 :margin)) 
            0 (second (send plot00 :margin)))
      (send plot01 :plot-buttons :bins t :new-x nil :new-y nil :mouse-mode nil
                   :hot-spot nil)
      (send plot10 :plot-buttons :bins t :new-x nil :new-y nil :mouse-mode nil
                   :hot-spot nil)
      (send plot11 :plot-buttons :bins t :new-x nil :new-y nil :mouse-mode nil
                   :hot-spot nil)
      (send plot00 :add-mouse-mode 'no-action
            :title "No Action" :click :do-nothing :cursor 'no-action)
      (send plot00 :mouse-mode 'no-action)
      (send plot01 :add-mouse-mode 'no-action
            :title "No Action" :click :do-nothing :cursor 'no-action)
      (send plot01 :mouse-mode 'no-action)
      (send plot10 :add-mouse-mode 'no-action
            :title "No Action" :click :do-nothing :cursor 'no-action)
      (send plot10 :mouse-mode 'no-action)
      (send plot11 :add-mouse-mode 'no-action
            :title "No Action" :click :do-nothing :cursor 'no-action)
      (send plot11 :mouse-mode 'no-action)
      (send plot01 :switch-add-normal)
      (send plot11 :switch-add-normal)
      (when (> *color-mode* 0)
            (send plot01 :use-color t)
            (send plot10 :use-color t)
            (send plot11 :use-color t))
      (send dob :spreadplot-object splot) 
      (setup-help splot plot00 plot01 plot10 plot11 nvars nobs)
      (defmeth plot00 :paint-function (color)
        (let* ((num-lines (send self :num-lines))
               (x (send self :linestart-coordinate 0 (iseq num-lines)))
               (y (send self :linestart-coordinate 1 (iseq num-lines)))
               (pixel-linestart-coordinates 
                (mapcar 
                 #'(lambda (i)
                     (send self :scaled-to-canvas 
                           (select x i) (select y i)))
                 (iseq num-lines)))
               (origin (+ (list 0 1) (send self :scaled-to-canvas 0 0)))
               (end (+ (list 0 1) (send self :scaled-to-canvas 
                                        (second (send self :range 0)) 0)))
               (pixel-linestart-coordinates
                (concatenate 'list pixel-linestart-coordinates 
                             (list end) (list origin) ))
               (prev-color (send self :draw-color)))
          (send self :clear-lines :draw nil)
          (send self :draw-color color)
          (send self :line-width 2)
          (send self :add-lines x y :color color :draw nil)
         ; (when (and (send self :use-color) (> *color-mode* 0))
         ;       (send self :paint-poly pixel-linestart-coordinates))
          (send self :line-width 1)
          (send self :draw-color prev-color)))
      (send plot00 :use-color t)
      (defmeth plot00 :redraw ()
        (call-next-method)
        (send self :paint-function 
              (if (or (not (send self :use-color)) (= *color-mode* 0) )
                  'black 'red)))
      (defmeth dob :update-from-spreadplot (i j args)
        "Method Args: none
Method to update statistical object. Closes open datasheet, then creates NSAMPLES new samples and adds them to the data object. Returns a list of new sample data. The list has NOBS*NSAMPLES elements. Updates Vars window."
        (let* ((dialog-results (send self :simulate-parameters))
               (nsamples (select dialog-results 2))
               (nobs (select dialog-results 1))
               (newsamples 
                (combine (transpose 
                          (matrix (list nsamples nobs)
                                  (send self :sample-data nsamples))))))
          (when (send self :datasheet-open) (send *datasheet* :close))
          (send self :data (combine (send self :data) newsamples))
          (send self :nvar (+ (send self :nvar) nsamples))
          (send self :variables 
                (mapcar #'(lambda (x) 
                            (format nil "Sample~a" x)) (iseq (send self :nvar))))
          (send self :types 
                (combine (send self :types) (repeat "Numeric" nsamples)))
          (send self :var-states 
                (combine (send self :var-states) (repeat 'normal nsamples)))
          (send self :datasheet-object nil)
          (send (send self :spreadplot-object) :update-spreadplot i j  newsamples)
          (send *vista* :show-labels)
          (send self :datatype (datatype?))
          ))
      (defmeth plot00 :update-plotcell (i j &rest args)
        (send self :redraw))
      (defmeth plot01 :update-plotcell (i j &optional newsamples)
        (when newsamples (setf newsamples (first newsamples)) 
              (let* ((list-of-lists 
                      (row-list (matrix (list nvars nobs) newsamples)))
                     (newmeans (mapcar #'mean list-of-lists))
                     )
                (send self :add-points newmeans  :draw nil)))
        (when (and (send self :use-color) (> *color-mode* 0))
              (send self :point-color (iseq (send self :num-points)) 'blue)
              (send self :point-state 
                    (iseq (send self :num-points)) 'hilited))
        (send self :switch-add-normal)
        (send self :adjust-to-data)
        (send self :switch-add-normal :line-width 2)
        (when (send self :subordinates)
              (let* ((slider (first (send self :subordinates)))
                     (sequence-item (third (send slider :items)))
                     (sequence 
                      (iseq 2 (floor (/ (send self :num-points) 2))))
                     )
                (send sequence-item :slot-value 'sequence sequence)
                (send sequence-item :slot-value 'XLISP::DISPLAY-SEQUENCE
                      sequence)
                (send sequence-item :max-value (- (length sequence) 1)))))
      (defmeth plot10 :update-plotcell (i j &optional newsamples)
        (when newsamples (setf newsamples (first newsamples))
              (let ((list-of-lists 
                     (row-list (matrix (list nvars nobs) newsamples))))
                (send self :clear)
                (send self :add-points (last list-of-lists) :draw nil)))
	(send self :adjust-to-data)
        (send self :use-color t)
        (send self :point-color (iseq (send self :num-points)) 'blue)
        (send self :point-state 
              (iseq (send self :num-points)) 'hilited)
        (send self :redraw)
        )
      (defmeth plot11 :update-plotcell (i j &optional newsamples)
        (when newsamples (setf newsamples (first newsamples))
              (let* ((list-of-lists 
                      (row-list (matrix (list nvars nobs) newsamples)))
                     (newstdvs 
                      (mapcar #'standard-deviation list-of-lists)))
                (send self :add-points newstdvs  :draw nil)))
        (when (and (send self :use-color) (> *color-mode* 0))
              (send self :point-color (iseq (send self :num-points)) 'blue)
              (send self :point-state 
                    (iseq (send self :num-points)) 'hilited))
        (send self :switch-add-normal)
        (send self :adjust-to-data)
        (send self :switch-add-normal :line-width 2)
        (when (send self :subordinates)
              (let* ((slider (first (send self :subordinates)))
                     (sequence-item (third (send slider :items)))
                     (sequence 
                      (iseq 2 (floor (/ (send self :num-points) 2))))
                     )
                (send sequence-item :slot-value 'sequence sequence)
                (send sequence-item :slot-value 'XLISP::DISPLAY-SEQUENCE
                      sequence)
                (send sequence-item :max-value (- (length sequence) 1)))))
      (send plot01 :update-plotcell 0 0)
      (send plot10 :update-plotcell 0 0)
      (send plot11 :update-plotcell 0 0)
      (send plot00 :redraw)
      (send plot01 :redraw)
      (send plot10 :redraw)
      (send plot11 :redraw)
      (mapcar #'(lambda (plot)
                  (defmeth plot :do-click (x y m1 m2)
	             (call-next-method x y m1 m2)))
           (list plot00 plot01 plot10 plot11))
      (send splot :show-spreadplot)
      (send *spreadplot-container* :title "Central Limit Theorem Visualization"))
     (list dob splot))))

(defun setup-help (splot plot00 plot01 plot10 plot11 nvars nobs)
  (defmeth splot :spreadplot-help ()
    (plot-help-window "SpreadPlot Help")
    (paste-plot-help (format nil "This is the Data Simulation SpreadPlot. It uses simulated data to demonstrate the Central Limit Theorem.~2%"))
    (paste-plot-help (format nil "The Central Limit Theorem says that for a continuous population distribution with any shape, the distributions of sample statistics such as means, standard deviations, etc., will tend to normal if the samples are sufficiently large (e.g., 30 or larger).~2%"))
    (paste-plot-help (format nil "To use this SpreadPlot, click on the NEW SAMPLE button at the bottom of the POPULATION DISTRIBUTION window. Each click on this button takes ~d new sample~a from the population. Each new sample has ~d observations. The ~anew sample is shown in the SAMPLE DISTRIBUTION window.~2%" nvars (if (> nvars 1) "s" "") nobs (if (> nvars 1) "last " "")))
    (paste-plot-help (format nil "The mean~a of the new sample~a added to the distribution of sample means shown in the SAMPLE MEANS window. The standard deviation~a added to the SAMPLE STANDARD DEVIATIONS window. These windows show the sampling distribution as a blue histogram, and the theoretically expected normal distribution as a red line.~2%" (if (> nvars 1) "s" "") (if (> nvars 1) "s are" " is") (if (> nvars 1) "s are" " is")))
    (paste-plot-help (format nil "If your samples are large enough, then as you generate more and more samples (by repeatedly clicking on the NEW SAMPLE button) the sampling distributions of means and standard deviations should become normal in shape, no matter what the shape of the population."))
    (show-plot-help))
  (defmeth plot00 :plot-help ()
    (plot-help-window (strcat "Help: " (send self :title)))
    (paste-plot-help  (format nil "This plot displays the theoretical shape of the population distribution. The shape is determined by the choice you made when you choose a distribution for the simulation.~2%"))
    (paste-plot-help  (format nil "The NEW SAMPLE button at the bottom of this window generates ~d new sample~a from this population every time you click on it. " nvars (if (> nvars 1) "s" "")))
    (show-plot-help))
  (defmeth plot10 :plot-help ()
    (plot-help-window (strcat "Help: " (send self :title)))
    (paste-plot-help (format nil "This plot displays a histogram of the last sample distribution that has been generated. Every time you click on the NEW SAMPLE button, ~d new sample~a generated~a The shape of the sample will approximate the population distribution.~2%" nvars (if (> nvars 1) "s are" " is") (if (> nvars 1) ", the last being shown here." ".")))
    (show-plot-help)
    (call-next-method :flush nil))
  (defmeth plot01 :plot-help ()
    (plot-help-window (strcat "Help: " (send self :title)))
    (paste-plot-help (format nil "This plot displays a histogram of the sampling distribution of means --- the distribution of the means of the samples that you have been generating. Every time you click on the NEW SAMPLE button, ~d new sample~a generated. The mean~a of the sample~a added to this histogram. ~2%" nvars (if (> nvars 1) "s are" " is") (if (> nvars 1) "s" "") (if (> nvars 1) "s are" " is")))
    (paste-plot-help (format nil "The shape of the sampling distribution of means will gradually approximate the normal distribution, regardless of the population distributions shape. The normal distribution that best fits the current sampling distribution is shown for reference. This distribution approximates the expected normal distribution (the width may differ from what is expected)."))
    (show-plot-help)
    (call-next-method :flush nil))
  (defmeth plot11 :plot-help ()
    (plot-help-window (strcat "Help: " (send self :title)))
    (paste-plot-help (format nil "This plot displays a histogram of the sampling distribution of standard deviations --- the distribution of the standard deviations of the samples that you have been generating. Every time you click on the NEW SAMPLE button, ~d new sample~a generated. The standard deviation~a of the sample~a added to this histogram. The shape of the sampling distribution of standard deviations will gradually approximate the normal distribution, regardless of the population distributions shape.  The normal distribution that best fits the current sampling distribution is shown for reference. This distribution approximates the expected normal distribution (the width may differ from what is expected).~2%" nvars (if (> nvars 1) "s are" " is") (if (> nvars 1) "s" "") (if (> nvars 1) "s are" " is")))
    (show-plot-help)
    (call-next-method :flush nil)))
  
(defun sd-dialog ()
    "Function Args: none
Simulate data dialog box. Returns a list of 6 or 7 elements: distribution number; sample size; nsamples; t for visualize; 1st and 2nd extra parameters (or nil). Returns nil when dialog canceled."
  (let* ((title (send text-item-proto :new "SIMULATE DATA DIALOG"))
         (dist-label (send text-item-proto :new "Population Distribution:"))
         (dist-choice (send choice-item-proto :new 
           (list "Normal Distribution" "T Distribution"	"F Distribution"
                 "Uniform Distribution" "Binomial Distribution"
                 "Chi-Sq Distribution" "Cauchy Distribution" 
                 "Poisson Distribution" "Beta Distribution" "Gamma Distribution"
                 ) :value 0))
         (prompt1   (send text-item-proto :new "Sample size"))
         (prompt2   (send text-item-proto :new "Number of Samples"))
         (samp-choices (send text-item-proto :new "Sampling Details:"))
         (samp-size (send edit-text-item-proto :new "   30"))
         (num-samps (send edit-text-item-proto :new "    3")) 
         (visual-text (send text-item-proto :new 
                        (format nil "----------~%Central Limit Theorem:")))
         (visual    (send choice-item-proto :new 
                          (list "Do Not Show Visualization"
                                "Show Visualization") :value 1))
         (cancel    (send modal-button-proto :new "Cancel" ()))
         (ok	(send button-item-proto :new "OK")) 
         (ok-action (send ok :action
           #'(lambda ()
           (let ((dialog (send ok :dialog)))
             (send dialog :modal-dialog-return
                   (list (send dist-choice :value)
                         (read-from-string (send samp-size :text))
                         (read-from-string (send num-samps :text))
                         (if (= 0 (send visual :value)) nil t)))))))
         (the-dialog (send modal-dialog-proto :new 
                           (list title
                                 (list (list dist-label dist-choice)
                                       (list samp-choices 
                                              (list (list prompt1 prompt2)
                                                    (list samp-size num-samps))
                                                    visual-text visual 
                                             (list ok cancel))))
                           :default-button ok))
         (dialog-results (send the-dialog :modal-dialog))
         (second-dialog-results nil))
    (when dialog-results
          (case (select dialog-results 0)
            (2  (setf second-dialog-results 
                      (second-dialog "F-Distribution" 
                                     "Number of Groups")))
            (4 (setf second-dialog-results 
                     (second-dialog "Binomial Distribution"
                                    "Parameter n" "Parameter p")))
            (5 (setf second-dialog-results
                     (second-dialog "Chi-Sq Distribution"
                                    "Degrees of freedom")))
            (7 (setf second-dialog-results 
                     (second-dialog "Poisson Distribution"
                                    "Lambda mean")))
            (8 (setf second-dialog-results 
                     (second-dialog "Beta distribution"
                                    "First exponent" "Second exponent")))
            (9 (setf second-dialog-results 
                     (second-dialog "Gamma distribution"
                                    "Exponent"))))
          (setf dialog-results 
                (combine dialog-results second-dialog-results)))
    dialog-results))

(defun second-dialog (title text1 &optional text2)
"Function Args: (title text1 &optional text2)
Function to control presentation of the second simulate data dialog box."
  (if text2 (second-dialog2 title text1 text2)
      (second-dialog1 title text1)))

(defun second-dialog2 (title text1 text2)
"Function Args: (title text1 text2)
Function to present the two-argument second simulate data dialog box."
      (let* ((title-text (send text-item-proto :new title))
             (n-prompt (send text-item-proto :new text1))
             (d-prompt (send text-item-proto :new text2))
             (n-df (send edit-text-item-proto :new "" :text-length 5))
             (d-df (send edit-text-item-proto :new "" :text-length 5))
             (cancel	(send modal-button-proto :new "Cancel" ()))
             (ok	(send button-item-proto :new "OK"))
             (ok-action (send ok :action
                      #'(lambda ()
                          (let ((dialog (send ok :dialog)))
                            (send dialog :modal-dialog-return
                                  (list (read-from-string (send n-df :text))
                                        (read-from-string (send d-df :text)))
                                  )))))
             (the-dialog (send modal-dialog-proto :new
                               (list
                                title
                                (list n-prompt n-df)
                                (list d-prompt d-df)
                                (list ok cancel))
                               :default-button ok))
             (results (send the-dialog :modal-dialog)))
        results))
  
(defun second-dialog1 (title text1)
"Function Args: (title text1)
Function to present the one-argument second simulate data dialog box."
      (let* ((title-text (send text-item-proto :new title))
             (n-prompt (send text-item-proto :new text1))
             (n-df (send edit-text-item-proto :new "" :text-length 5))
             (cancel	(send modal-button-proto :new "Cancel" ()))
             (ok	(send button-item-proto :new "OK"))
             (ok-action (send ok :action
                      #'(lambda ()
                          (let ((dialog (send ok :dialog)))
                            (send dialog :modal-dialog-return
                                  (list (read-from-string
                                         (send n-df :text))))))))
             (the-dialog (send modal-dialog-proto :new
                               (list
                                title
                                (list n-prompt n-df)
                                (list ok cancel))
                               :default-button ok))
             (results (send the-dialog :modal-dialog)))
        results))

(defmeth mv-data-object-proto :pop-distribution (dialog-results)
"Method Args: (dialog-results)
Method to prepare information for the population distribution plot."
  (let* ((dialog-results (send self :simulate-parameters))
         (dist-type (select dialog-results 0))
         (nobs (select dialog-results 1))
         (arg1 (if (> (length dialog-results) 4) (select dialog-results 4)))
         (arg2 (if (> (length dialog-results) 5) (select dialog-results 5)))
         (x nil)
         (y nil))
    (case dist-type
      (0 (setf x (rseq -4 4 51))
         (setf y (normal-dens x)))
      (1 (setf x (rseq -4 4 51))
         (setf y (t-dens x (- nobs 1))))
      (2 (setf x (rseq 0 6 51))
         (setf y (f-dens x arg1 (- nobs arg1))))
      (3 (setf x (list 0 1))
         (setf y (list 1 1)))
      (4 (setf x (iseq 0 arg1))
         (setf y (binomial-pmf x arg1 arg2)))
      (5 (setf x (rseq 0 75 51))
         (setf y (chisq-dens x arg1)))
      (6 (setf x (rseq -2 2 51))
         (setf y (cauchy-dens x)))
      (7 (setf x (iseq 0 nobs))
         (setf y (poisson-pmf x arg1)))
      (8 (setf x (rseq 0 0.9999999 51))
         (setf y (beta-dens x arg1 arg1)))
      (9 (setf x (rseq 0 nobs 51))
         (setf y (gamma-dens x arg1)))
      )
    (list x y)))

(defmeth mv-data-object-proto :sample-data (nsamples)
  (sample-data nsamples (send self :simulate-parameters)))

(defun sample-data (nsamples dialog-results)
"Method Args: (nsamples &optional dialog-results)
Method to generate NSAMPLES of simulated data for NOBS observations. Returns the samples as a single list. The first NOBS elements are for the first sample, the second NOBS elements for the next sample, etc."
  (let* ((dist) (nobs) (arg1) (arg2))
    (setf dist (select dialog-results 0)) 
    (setf nobs (select dialog-results 1)) 
    (setf arg1 (if (> (length dialog-results) 4) (select dialog-results 4)))
    (setf arg2 (if (> (length dialog-results) 5) (select dialog-results 5)))
    (case dist
      (0 (normal-rand (* nobs nsamples)))
      (1 (t-rand (* nobs nsamples) (- nobs 1)))
      (2 (f-rand (* nobs nsamples) arg1 (- nobs arg1)))
      (3 (uniform-rand (* nobs nsamples)))
      (4 (binomial-rand (* nobs nsamples) arg1 arg2))
      (5 (chisq-rand (* nobs nsamples) arg1))
      (6 (cauchy-rand (* nobs nsamples)))
      (7 (poisson-rand (* nobs nsamples) arg1))
      (8 (beta-rand (* nobs nsamples) arg1 arg2))
      (9 (gamma-rand (* nobs nsamples) arg1)))))

(defproto newsamp-overlay-proto '(x y) () graph-overlay-proto)

(defmeth newsamp-overlay-proto :isnew (&rest args)
  (apply #'call-next-method args)
  )

(defmeth newsamp-overlay-proto :x (&optional (val nil set))
  (if set (setf (slot-value 'x) val))
  (slot-value 'x))

(defmeth newsamp-overlay-proto :y (&optional (val nil set))
  (if set (setf (slot-value 'y) val))
  (slot-value 'y))

(defmeth newsamp-overlay-proto :resize ()
  (send self :x nil)
  (call-next-method))

(defmeth newsamp-overlay-proto :redraw ()
  (let* ((graph (send self :graph))
         (draw-color (send graph :draw-color))
         (x (send self :x))
         (y (send self :y)))
    (when (not x) 
          (setf x 10)
          (setf y (- (send graph :canvas-height) 15))
          (send self :x x)
          (send self :y y))
    (if (and (send graph :use-color) (< 0 *color-mode*))
        (send graph :draw-color 'toolbar-background)
        (send graph :draw-color 'white))
    (send graph :paint-rect 0 y (send graph :canvas-width) 15)
    (send graph :draw-color draw-color)
    (send graph :draw-line 0 y (send graph :canvas-width) y)
    (send self  :draw-button nil x (+ 3 y) 10 10)
    (send graph :draw-string "New Sample" (+ x 14) (+ y 9 3))
    ))

(defmeth newsamp-overlay-proto :do-click (x y m1 m2)
  (let* ((button-x (send self :x)) 
         (button-y (+ 3 (send self :y)))
         (graph (send self :graph))
         (spreadplot (send graph :spreadplot-object))
         (y-limits (- (send graph :canvas-height) 13)))
    (send self :draw-button t button-x button-y 10 10)
    (when (and (< 10 x 20) (< y-limits y (+ y-limits 10)))
          (send spreadplot :update-spreadplot 0 0 :use-statobj t))
    (send self :draw-button nil button-x button-y 10 10)))

(defmeth newsamp-overlay-proto :draw-button (paint a b c d)
  (let ((graph (send self :graph)))
    (when paint 
          (send graph :draw-color 
                (if (or (not (send graph :use-color))
                        (= *color-mode* 0)) 'black 'button-on-color))
          (send graph :paint-rect a b c d)
          (send graph :draw-color 'black)
          (send graph :frame-rect a b c d))
    (when (not paint)
          (send graph :draw-color 'white)
          (send graph :paint-rect a b c d)
          (send graph :draw-color 'black)
          (send graph :frame-rect a b c d))))